#pragma once

#include <iostream>
#include <string>
#include <time.h>
#include <atomic>

#include <unistd.h>
#include <sys/time.h>
#include <fstream>

using std::string;

#define TEMP_PATH "./temp/" // 编译运行过程产生的临时文件所在目录

namespace ns_utils
{
    class TimeUtil
    {
    public:
        /**
         * @brief 打印当前时间
         *
         * @return 时间字符串
         */
        static string get_time()
        {
            time_t t;
            struct tm* tmp;
            char buf[32] = {0};

            time(&t);
            tmp = localtime(&t);
            strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M",tmp);
            string res = buf;

            return res;
        }

        /**
         * @brief 打印当前毫秒时间戳
         *
         * @return 时间戳
         */
        static string get_timestamp()
        {
            struct timeval time;
            gettimeofday(&time, nullptr);
            string timestamp = std::to_string(time.tv_sec*1000\
                + time.tv_usec / 1000);

            return timestamp;
        }
    };

    class PathUtil
    {
    private:
        /**
         * @brief 为文件添加指定后缀名
         *
         * @param[in] file 文件名
         *
         * @param[in] suffix 后缀名
         *
         * @return 完整文件文件名
         */
        static string add_suffix(const string& file,const string& suffix)
        {
            /* 生成的临时文件所在目录由TEMP_PATH指定 */
            string path_name = TEMP_PATH;
            path_name += file;
            path_name += suffix;

            return path_name;
        }
    public:
        static string src_file(const string& file)
        {
            return add_suffix(file,".cpp");
        }

        static string exec_file(const string& file)
        {
            return add_suffix(file,".exe");
        }

        static string compile_err_file(const string& file)
        {
            return add_suffix(file,".compile_err");
        }

        static string stdin_file(const string& file)
        {
            return add_suffix(file,".stdin");
        }

        static string stdout_file(const string& file)
        {
            return add_suffix(file,".stdout");
        }

        static string stderr_file(const string& file)
        {
            return add_suffix(file,".stderr");
        }
    };

    class FileUtil
    {
    public:
        /**
         * @brief 判断文件是否存在
         *
         * @param[in] file_name 文件名
         *
         * @return true 或 false
         */
        static bool is_file_exists(const string& file_name)
        {
            struct stat info;
            if(0 == stat(file_name.c_str(),&info))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /**
         * @brief 根据时间戳与原子性id生成一个唯一文件名
         *
         * @return 唯一文件名
         */
        static string unique_file()
        {
            /* 原子性id */
            static std::atomic_uint id(0);
            id++;

            string timestamp = TimeUtil::get_timestamp();
            string unique_id = std::to_string(id);

            return timestamp+"_"+unique_id;
        }

        /**
         * @brief 读取文件内容到字符串中
         *
         * @param[in] file_name 文件名
         *
         * @param[out] content 保存文件内容的字符串
         *
         * @param[in] keep 是否保留换行符,默认不保留
         *
         * @return 读取文件内容是否成功
         */
        static bool read_file(const string& file_name,string* content,bool keep = false)
        {
            std::ifstream in(file_name);
            if(!in.is_open())
            {
                return false;
            }

            (*content).clear();
            string line; // 暂存文件每一行内容
            while(getline(in,line)) // getline默认不保留分隔符
            {
                *content += line;
                if(keep)
                {
                    *content += "\n";
                }
            }
            in.close();

            return true;
        }

        /**
         * @brief 写入内容到文件中
         *
         * @param[in] file_name 文件名
         *
         * @param[in] content 待写入的内容
         *
         * @return 写入文件是否成功
         */
        static bool write_file(const string& file_name,const string& content)
        {
            std::ofstream out(file_name);
            if(!out.is_open())
            {
                return false;
            }

            out.write(content.c_str(),content.size());
            out.close();

            return true;
        }
    };

    class StringUtil
    {
    public:
        /**
         * @brief 根据分隔符分离子串到容器中
         *
         * @param[in] str 源字符串
         *
         * @param[out] res 存放子串的容器
         *
         * @param[in] separator 分隔符
         *
         * @param[in] compres  是否压缩多个分隔符为一个分隔符
         *
         */
        static void split_string(const string& str,std::vector<string>* res,const char separator,const bool compress = true)
        {
            size_t beg = 0;
            size_t end = 0;
            res->clear();
            while((end = str.find(separator,beg)) != string::npos)
            {
                res->push_back(str.substr(beg,end-beg));
                beg = end + 1;
                if(compress)
                {
                    while(beg < str.size() && str[beg] == separator)
                    {
                        beg++;
                    }
                }
            }

            /* 如果beg小于str.size(),说明从beg到字符串结尾没有分隔符，即将[beg,end]作为最后一个子串添加到容器中 */
            if(beg < str.size())
            {
                res->push_back(str.substr(beg,string::npos));
            }
        }
    };
}
